package com.ml.customannotation.aop.aspect;

import com.google.common.base.Preconditions;
import com.ml.customannotation.aop.customAnnotation.Biz;
import com.ml.customannotation.aop.customAnnotation.BizTemplate;
import com.ml.customannotation.aop.customAnnotation.NoCheck;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Objects;

/**
 * Biz注解处理类
 *
 * @author zhaozongyi@mmears.com
 * @date 2021-05-17
 * @time 11:22
 */
//@Aspect
@Slf4j
//@Component
public class BizAspect {

    private static final String EMPTY_MSG = " is empty.";

    @Pointcut(value="execution(* com.ml.customannotation.aop.biz.impl.*.*(..))")
    private void pointcut() {
    }

    @Pointcut(value="@annotation(biz)")
    private void pointcutAnno(Biz biz) {
    }

    @Around(value = "pointcut()")
    public Object biz(ProceedingJoinPoint point) throws Throwable {
        log.info("--------");
//        log.info("point.getClass():{}",point.getClass());//ProceedingJoinPoint
//        log.info("point.getClass():{}",point.getTarget());//注解所在类
//        log.info("point.getClass():{}",point.getThis());//注解所在类
        log.info("--------");
        //获取方法上的注解以及注解属性
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (Objects.isNull(method)) {
            return point.proceed();
        }
        Biz biz = method.getAnnotation(Biz.class);
        if (Objects.isNull(biz)) {
            return point.proceed();
        }
        boolean checkParam = biz.checkParam();

        //获取参数值列表
        Object[] args = point.getArgs();
        //获取参数类型列表
        Parameter[] parameters = method.getParameters();
        return new BizTemplate<Object>() {

            @Override
            protected void checkParams() {
                if (checkParam
                        && Objects.nonNull(args) && args.length > 0
                        && Objects.nonNull(parameters) && args.length == parameters.length) {
                    //参数校验代码填充
                    NoCheck noCheck = null;
                    for (int i = 0; i < args.length; i++) {
                        noCheck = parameters[i].getAnnotation(NoCheck.class);
                        if(Objects.isNull(noCheck)){
                            Preconditions.checkNotNull(args[i], parameters[i].getName() + EMPTY_MSG);
                        }
                    }
                }
            }

            @Override
            public Object process() throws Throwable {
                return point.proceed();
            }

        }.execute();
    }
}

//另外一种获取方法上的注解以及参数类型的方式
//    Method method = null;
//    Class[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes();
//        try {
//           method = point.getTarget().getClass().getMethod(point.getSignature().getName(), parameterTypes);
//        } catch (NoSuchMethodException e) {
//           e.printStackTrace();
//        }
//        if (method != null) {
//           System.out.println(Arrays.asList(method.getAnnotations()));
//        }
